import Geo from './Geo';
import Mat from './Mat';
import Scene from './Scene';
import { locationName } from "./Interface";
import { getParentIsRoot, getChildren } from '../Component';


interface obj3DData {
    geo?: Geo;
    mat?: Mat;
}

export default class Obj3D {
    geo?: Geo;
    mat?: Mat;

    children: Obj3D[] = [];
    parent: Obj3D | Scene | null = null;

    public constructor(data: obj3DData) {
        this.mat = data.mat;
        this.geo = data.geo;
    }

    public init(device: GPUDevice) {
        const { mat, geo } = this;
        geo && geo.init(device);
        mat && mat.init(device);
    }

    public update(
        device: GPUDevice,
        renderPass: GPURenderPassEncoder,
        location: Map<string, locationName>
    ) {
        const { mat, geo, children } = this;
        mat && mat.update(device, renderPass, location);
        geo && geo.update(device, renderPass, location);
    }

    public draw(renderPass: GPURenderPassEncoder) {
        const { mat, geo } = this;

        if (!(mat == null || geo == null)) {
            renderPass.draw(geo.verticeCount);
        }
    }

    public add(device: GPUDevice, ...child: Obj3D[]) {
        const { children } = this;
        for (let obj of child) {
            children.push(obj);
            obj.init(device);

            //查询父类是否在已经加载
            if (getParentIsRoot(this)) {
                //以加载,加载的子类全部init

                const arr = getChildren(obj);
                for (let obj of child) {
                    obj.init(device!);
                    Scene.scene.addDrawMap(obj);
                }
            } else {
                //未加载 统一加载
            }
        }
    }

    public setAttrib(name: string, array: Float32Array) {
        const { geo, children } = this;
        geo && geo.setData(name, array);

        children.forEach(u => {
            u.setAttrib(name, array);
        })
    }

    public setUniform(name: string, array: Float32Array) {
        const { mat, children } = this;
        mat && mat.setData(name, array);

        children.forEach(u => {
            u.setUniform(name, array);
        })
    }


    public getType() {
        return Obj3D.name;
    }

}